package com.qinsilk.axon.inventory

import com.qinsilk.axon.inventory.query.InventoryQueryModel
import com.qinsilk.axon.inventory.query.InventoryRepository
import org.axonframework.eventsourcing.eventstore.EventStore
import org.springframework.web.bind.annotation.*

@RestController
@RequestMapping("/demo")
class TimeTravelDemoController(
        private val eventStore: EventStore,
        private val inventoryRepository: InventoryRepository
) {

    @GetMapping("/events/{inventoryId}")
    fun getEventHistory(@PathVariable inventoryId: String): List<Map<String, Any>> {
        return eventStore
                .readEvents(inventoryId)
                .asStream()
                .map { message ->
                    val payload = message.payload
                    val eventMap = mutableMapOf<String, Any>()

                    // 复制原始事件属性
                    val payloadFields = payload.javaClass.declaredFields
                    for (field in payloadFields) {
                        field.isAccessible = true
                        eventMap[field.name] = field.get(payload) ?: ""
                    }

                    // 添加事件类型信息
                    eventMap["eventType"] = payload.javaClass.simpleName

                    eventMap
                }
                .toList()
    }

    @GetMapping("/state/{inventoryId}")
    fun getCurrentState(@PathVariable inventoryId: String): InventoryQueryModel? {
        return inventoryRepository.findById(inventoryId).orElse(null)
    }

    // 时间穿梭功能：根据事件ID重建聚合状态
    @GetMapping("/time-travel/{inventoryId}/{eventId}")
    fun getTimeTravelState(
            @PathVariable inventoryId: String,
            @PathVariable eventId: String
    ): Map<String, Any> {
        // 获取所有事件
        val events = eventStore.readEvents(inventoryId).asStream().toList()

        // 找到指定事件的位置
        val targetEventIndex =
                events.indexOfFirst {
                    val payload = it.payload
                    // 检查事件是否包含eventId字段并匹配
                    try {
                        // 对于包含eventId字段的事件类型
                        val eventIdField = payload.javaClass.getDeclaredField("eventId")
                        eventIdField.isAccessible = true
                        val eventFieldValue = eventIdField.get(payload)?.toString()
                        eventFieldValue == eventId
                    } catch (e: NoSuchFieldException) {
                        // 对于不包含eventId字段的事件（如InventoryCreatedEvent），使用事件标识符
                        it.identifier.toString() == eventId
                    } catch (e: Exception) {
                        false
                    }
                }

        if (targetEventIndex == -1) {
            throw IllegalArgumentException("未找到指定的事件ID: $eventId")
        }

        // 只处理到目标事件为止的所有事件
        val eventsToReplay = events.subList(0, targetEventIndex + 1)

        // 重建聚合状态
        var quantity = 0
        var productName = ""
        var lastEvent = ""

        for (eventMessage in eventsToReplay) {
            val event = eventMessage.payload
            when (event) {
                is com.qinsilk.axon.inventory.command.InventoryCreatedEvent -> {
                    quantity = event.initialQuantity
                    productName = event.productName
                    lastEvent = "创建库存"
                }
                is com.qinsilk.axon.inventory.command.StockInRecordedEvent -> {
                    quantity += event.quantity
                    lastEvent = "入库: ${event.reason}"
                }
                is com.qinsilk.axon.inventory.command.StockOutRecordedEvent -> {
                    quantity -= event.quantity
                    lastEvent = "出库: ${event.reason}"
                }
                is com.qinsilk.axon.inventory.command.OperationCancelledEvent -> {
                    when (event.eventType) {
                        "StockInRecordedEvent" -> quantity -= event.quantity
                        "StockOutRecordedEvent" -> quantity += event.quantity
                    }
                    lastEvent = "撤销操作: ${event.eventType}"
                }
            }
        }

        return mapOf(
                "inventoryId" to inventoryId,
                "productName" to productName,
                "quantity" to quantity,
                "lastEvent" to lastEvent,
                "replayedEventsCount" to eventsToReplay.size
        )
    }
}
